using System;
using System.Collections.Generic;
using System.Linq;

namespace Limestone
{
    public class TemplateProvider:ITemplateProvider
    {
        public IStorage Storage { get; set; }

        public TemplateProvider(IStorage storage)
        {
            Storage = storage;
        }

        /// <summary>
        /// Loads and returns a full template object.
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public IPageTemplate Get(string path)
        {
            return Storage.GetTemplate(path);
        }

        public IEnumerable<IPageTemplate> GetAll()
        {
            return Storage.GetTemplates();
        }

        /// <summary>
        /// Ensures that the page has all the fields declared in the template and removes any excess fields from the page
        /// </summary>
        /// <param name="page"></param>
        public void SyncPageWithTemplate(IPage page)
        {
            var template = Get(page.TemplatePath);

            if (template == null)
                return;

            // add missing fields
            foreach (var fieldSetting in template.FieldSettings)
            {
                var fld = page.Fields[fieldSetting.Name];
                if (fld != null && fld.Type != fieldSetting.Type)
                {
                    page.Fields.Remove(fld);
                    fld = null;
                }

                if (fld == null)
                {
                    fld = (Field)FieldFactory.CreateField(fieldSetting.Type);
                    fld.Name = fieldSetting.Name;
                    page.Fields.Add(fld);
                }
            }

            // remove excess fields
            var fieldsToRemove = (from field in page.Fields where template.FieldSettings[field.Name] == null select field.Name).ToList();
            foreach (var fieldName in fieldsToRemove)
            {
                page.Fields.Remove(page.Fields[fieldName]);
            }
        }


        /// <summary>
        /// Loads fieldsettings from the template and appends them to their respective field in the page
        /// </summary>
        /// <param name="page"></param>
        public void AddFieldSettings(IPage page)
        {
            var template = Get(page.TemplatePath);

            if (template == null)
                return;

            foreach (var fieldSetting in template.FieldSettings)
            {
                var fld = page.Fields[fieldSetting.Name];
                if (fld == null)
                {
                    throw new Exception("Field missing in page. To avoid these exceptions, call SyncPageWithTemplate() first.");
                }
                if (fld.Type != fieldSetting.Type)
                {
                    throw new Exception("Field type in page differs from tield type in template. To avoid these exceptions, call SyncPageWithTemplate() first.");
                }

                // append the field settings from the template to the page's field
                page.Fields[fieldSetting.Name].Settings = fieldSetting;
            }
        }

        /// <summary>
        /// persists the template to disc
        /// </summary>
        /// <returns></returns>
        public IPageTemplate Save(IPageTemplate template)
        {
            // TODO unique name in this folder
            return Storage.SaveTemplate(template);
        }
    }
}